
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

public class SmoothNormalsToTangentEditor : EditorWindow
{
    private GameObject targetObject;
    private bool showDebugInfo = false;
    
    [MenuItem("Tools/法线工具/平滑法线转切线")]
    public static void ShowWindow()
    {
        GetWindow<SmoothNormalsToTangentEditor>("平滑法线工具");
    }
    
    void OnGUI()
    {
        GUILayout.Label("平滑法线转切线工具", EditorStyles.boldLabel);
        
        targetObject = (GameObject)EditorGUILayout.ObjectField("目标模型", targetObject, typeof(GameObject), true);
        
        EditorGUILayout.Space();
        
        if (GUILayout.Button("处理选中模型"))
        {
            if (targetObject != null)
            {
                ProcessModel(targetObject);
            }
            else
            {
                EditorUtility.DisplayDialog("错误", "请先选择目标模型", "确定");
            }
        }
        
        showDebugInfo = EditorGUILayout.Toggle("显示调试信息", showDebugInfo);
        
        EditorGUILayout.Space();
        EditorGUILayout.HelpBox("此工具将平滑后的法线数据存储到切线中，用于解决硬表面模型描边断裂问题。", MessageType.Info);
    }
    
    private void ProcessModel(GameObject target)
    {
        MeshFilter meshFilter = target.GetComponent<MeshFilter>();
        SkinnedMeshRenderer skinnedMesh = target.GetComponent<SkinnedMeshRenderer>();
        
        Mesh mesh = null;
        bool isSkinned = false;
        
        if (skinnedMesh != null)
        {
            mesh = skinnedMesh.sharedMesh;
            isSkinned = true;
        }
        else if (meshFilter != null)
        {
            mesh = meshFilter.sharedMesh;
        }
        
        if (mesh == null)
        {
            EditorUtility.DisplayDialog("错误", "未找到Mesh数据", "确定");
            return;
        }
        
        // 创建新的Mesh实例以避免修改原始资源
        Mesh newMesh = Instantiate(mesh);
        newMesh.name = mesh.name + "_SmoothNormals";
        
        // 计算平滑法线
        Vector3[] smoothNormals = CalculateSmoothNormals(newMesh);
        
        // 将平滑法线存储到切线
        StoreNormalsInTangents(newMesh, smoothNormals);
        
        // 保存处理后的Mesh
        if (isSkinned)
        {
            skinnedMesh.sharedMesh = newMesh;
        }
        else
        {
            meshFilter.sharedMesh = newMesh;
        }
        
        // 创建Asset文件
        SaveMeshAsAsset(newMesh, target.name);
        
        if (showDebugInfo)
        {
            Debug.Log($"成功处理模型: {target.name}, 顶点数: {newMesh.vertexCount}");
        }
        
        EditorUtility.DisplayDialog("完成", $"模型 {target.name} 处理完成", "确定");
    }
    
    private Vector3[] CalculateSmoothNormals(Mesh mesh)
    {
        Vector3[] vertices = mesh.vertices;
        Vector3[] normals = mesh.normals;
        Vector3[] smoothNormals = new Vector3[normals.Length];
        
        // 使用字典优化性能，避免O(n²)复杂度
        Dictionary<Vector3, List<int>> vertexGroups = new Dictionary<Vector3, List<int>>();
        
        // 按顶点位置分组
        for (int i = 0; i < vertices.Length; i++)
        {
            if (!vertexGroups.ContainsKey(vertices[i]))
            {
                vertexGroups[vertices[i]] = new List<int>();
            }
            vertexGroups[vertices[i]].Add(i);
        }
        
        // 对每组位置相同的顶点计算平均法线
        foreach (var group in vertexGroups.Values)
        {
            Vector3 averageNormal = Vector3.zero;
            
            foreach (int index in group)
            {
                averageNormal += normals[index];
            }
            
            averageNormal.Normalize();
            
            foreach (int index in group)
            {
                smoothNormals[index] = averageNormal;
            }
        }
        
        return smoothNormals;
    }
    
    private void StoreNormalsInTangents(Mesh mesh, Vector3[] smoothNormals)
    {
        Vector4[] tangents = new Vector4[mesh.vertexCount];
        
        for (int i = 0; i < mesh.vertexCount; i++)
        {
            // 将平滑法线存储到切线向量的xyz分量
            // w分量可以用于存储其他信息，如描边粗细
            tangents[i] = new Vector4(
                smoothNormals[i].x,
                smoothNormals[i].y, 
                smoothNormals[i].z,
                1.0f // 默认描边粗细
            );
        }
        
        mesh.tangents = tangents;
    }
    
    private void SaveMeshAsAsset(Mesh mesh, string objectName)
    {
        string path = EditorUtility.SaveFilePanel(
            "保存处理后的Mesh",
            "Assets",
            objectName + "_SmoothNormals",
            "asset"
        );
        
        if (!string.IsNullOrEmpty(path))
        {
            path = FileUtil.GetProjectRelativePath(path);
            AssetDatabase.CreateAsset(mesh, path);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
    }
}
